package SmartGrid;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import Plants.GraphAlgorithms;
import Plants.PowerPlant;
import Tasks.ManageSmartGrid;
import Tools.SmartGridFileReader;


/**
 * Contains the graph data structure of the power plants and power lines.
 * Is responsible for distributing power from power plants to consumers
 * @author jeffrey
 *
 */
public class SmartGrid {
	
	public static Map<String, PowerPlant> allPlants;
	
	/**
	 * Initialize a new Smart Grid
	 */
	public SmartGrid()
	{
		allPlants = new HashMap<String, PowerPlant>();
		initAllPowerLevels();
	}
	
	/**
	 * Initialize a new Smart Grid and populates it from a file.
	 * Deploys Floyd Warshall algorithm to cache shortest distances and paths
	 * @param filename the text file that contains power plants and power lines
	 */
	public SmartGrid(String filename)
	{
		allPlants = SmartGridFileReader.populateSmartGridFromFile(filename);
		GraphAlgorithms.FloydWarshall();
		initAllPowerLevels();
	}
	
	/**
	 * Initialize power plants and start producing electricity
	 */
	private void initAllPowerLevels()
	{
		Iterator<String> iter = allPlants.keySet().iterator();
		while(iter.hasNext())
		{
			String key = iter.next();
			PowerPlant p = allPlants.get(key);
			p.setElectricOutput(Tools.Options.INIT_POWER_LEVEL, false);
			p.setAvailableEnergy(Tools.Options.INIT_POWER_LEVEL, true);
		}
		EnergyMarket.supply.getAndAdd(allPlants.keySet().size() * Tools.Options.INIT_POWER_LEVEL);
	}
	
	/**
	 * Deploys the core grid management algorithm on a separate thread
	 */
	public void manage()
	{
		ManageSmartGrid management = new ManageSmartGrid(this);
		ExecutionEngine.addRecurringTask(management, Tools.Options.MANAGE_SMART_GRID_DELAY);
	}
	
	public void addPlant(PowerPlant p)
	{
		allPlants.put(p.getName(), p);
	}
	
	public Set<PowerPlant> getAllPlants()
	{
		Set<PowerPlant> plants = new HashSet<PowerPlant>();
		plants.addAll(allPlants.values());
		return plants;
	}
	
	public PowerPlant getPlant(String name)
	{
		return allPlants.get(name);
	}
	
	/**
	 * Gets a random power plant from the grid
	 * @return
	 */
	public static PowerPlant getRandomPlant()
	{
		Random rand = new Random();
		int index = rand.nextInt(allPlants.size());
		Iterator<PowerPlant> iter = allPlants.values().iterator();
		for(int i = 0; i < index; i++)
		{
			iter.next();
		}
		return iter.next();
	}
	
	/**
	 * Gets a random consumer from a random power plant
	 * @return
	 */
	public static ConsumerEnergyMeter getRandomConsumer()
	{
		Random rand = new Random();
		int plantIndex = rand.nextInt(allPlants.size());
		Iterator<PowerPlant> iter = allPlants.values().iterator();
		for(int i = 0; i < plantIndex; i++)
		{
			iter.next();
		}
		PowerPlant plant = iter.next();
		int consumerIndex = rand.nextInt(plant.getConsumers().size());
		return plant.getConsumers().get(consumerIndex);
	}
	
	/**
	 * Prints the network in this grid to the console.
	 * Gives information on which power plants are connected to which power plants.
	 */
	public void printNetwork()
	{
		Iterator<String> iter = allPlants.keySet().iterator();
		while(iter.hasNext())
		{
			String key = iter.next();
			PowerPlant p = allPlants.get(key);
			System.out.println(p.toString());
		}
	}
	
	/**
	 * Prints each power plant's electric output and available energy to the console
	 */
	public void printEnergyLevels()
	{
		Iterator<String> iter = allPlants.keySet().iterator();
		while(iter.hasNext())
		{
			String key = iter.next();
			PowerPlant p = allPlants.get(key);
			System.out.println(p.getName() + " Energy Output: " + p.getElectricOutput() + " Available Energy: " + p.getAvailableEnergy());
		}
	}
	
	@Override
	public String toString()
	{
		String smartgrid = "";
		Iterator<String> iter = allPlants.keySet().iterator();
		while(iter.hasNext())
		{
			String key = iter.next();
			PowerPlant p = allPlants.get(key);
			int electricOutput = p.getElectricOutput();
			int availableEnergy = p.getAvailableEnergy();
			List<ConsumerEnergyMeter> consumers = p.getConsumers();
			smartgrid += "" + key + " " + electricOutput + " " + availableEnergy + " ";
			for(int i = 0; i < consumers.size(); i++)
			{
				ConsumerEnergyMeter c = consumers.get(i);
				if(i != consumers.size()-1)
					smartgrid += c.getEnergyDemand() + " ";
				else
					smartgrid += c.getEnergyDemand() + "\n";
			}
		}
		return smartgrid;
	}
	
}
